package com.java110.job.task.fee;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.java110.core.client.RestTemplate;
import com.java110.core.factory.CallApiServiceFactory;
import com.java110.core.factory.GenerateCodeFactory;
import com.java110.core.smo.IComputeFeeSMO;
import com.java110.dto.account.AccountDetailDto;
import com.java110.dto.account.AccountDto;
import com.java110.dto.app.AppDto;
import com.java110.dto.community.CommunityDto;
import com.java110.dto.fee.FeeDto;
import com.java110.dto.log.LogSystemErrorDto;
import com.java110.dto.store.StoreUserDto;
import com.java110.dto.task.TaskDto;
import com.java110.intf.acct.IAccountInnerServiceSMO;
import com.java110.intf.common.ILogSystemErrorInnerServiceSMO;
import com.java110.intf.fee.IFeeInnerServiceSMO;
import com.java110.intf.store.IStoreUserV1InnerServiceSMO;
import com.java110.job.quartz.TaskSystemQuartz;
import com.java110.po.account.AccountDetailPo;
import com.java110.po.log.LogSystemErrorPo;
import com.java110.service.smo.ISaveSystemErrorSMO;
import com.java110.utils.constant.ServiceCodeConstant;
import com.java110.utils.exception.SMOException;
import com.java110.utils.util.Assert;
import com.java110.utils.util.DateUtil;
import com.java110.utils.util.ExceptionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;

/**
 * @ClassName GenerateOwnerBillTemplate
 * @Description TODO  预存账户扣款缴费
 * @Author wuxw
 * @Date 2020/6/4 8:33
 * @Version 1.0
 * add by wuxw 2020/6/4
 **/
@Component
public class AccountDeductionPayFeeTemplate extends TaskSystemQuartz {


    @Autowired
    private IFeeInnerServiceSMO feeInnerServiceSMOImpl;

    @Autowired
    private IComputeFeeSMO computeFeeSMOImpl;

    @Autowired
    private ILogSystemErrorInnerServiceSMO logSystemErrorInnerServiceSMOImpl;

    @Autowired
    private ISaveSystemErrorSMO saveSystemErrorSMOImpl;

    @Autowired
    private IAccountInnerServiceSMO accountInnerServiceSMOImpl;

    @Autowired
    private IStoreUserV1InnerServiceSMO storeUserV1InnerServiceSMOImpl;

    @Autowired
    RestTemplate restTemplate;

    @Override
    protected void process(TaskDto taskDto) throws Exception {

        // 获取小区
        List<CommunityDto> communityDtos = getAllCommunity();

        for (CommunityDto communityDto : communityDtos) {
            doDeductionPayFeeFee(taskDto, communityDto);
        }

    }

    /**
     * 根据小区生成账单
     *
     * @param communityDto
     */
    private void doDeductionPayFeeFee(TaskDto taskDto, CommunityDto communityDto) {

        //查询费用项
        AccountDto accountDto = new AccountDto();
        accountDto.setPartId(communityDto.getCommunityId());
        accountDto.setHasMoney("1");
        accountDto.setFreeze("0");  //非冻结的业主账户才可以自动冲抵
        accountDto.setAcctType(AccountDto.ACCT_TYPE_CASH);
        List<AccountDto> accountDtos = accountInnerServiceSMOImpl.queryAccounts(accountDto);

        if (accountDtos == null || accountDtos.size() < 1) {
            return;
        }

        for (AccountDto tmpAccountDto : accountDtos) {
            try {
                doPayFee(tmpAccountDto);
            } catch (Exception e) {
                LogSystemErrorPo logSystemErrorPo = new LogSystemErrorPo();
                logSystemErrorPo.setErrId(GenerateCodeFactory.getGeneratorId(GenerateCodeFactory.CODE_PREFIX_errId));
                logSystemErrorPo.setErrType(LogSystemErrorDto.ERR_TYPE_JOB);
                logSystemErrorPo.setMsg(ExceptionUtil.getStackTrace(e));
                saveSystemErrorSMOImpl.saveLog(logSystemErrorPo);
                logger.error("生成费用失败", e);
            }
        }

    }

    private void doPayFee(AccountDto tmpAccountDto) {
        //如果账户余额为0则直接返回
        if (Double.parseDouble("0") == Double.parseDouble(tmpAccountDto.getAmount())) {
            return; // 余额不足
        }
        // 查询业主的费用
        FeeDto feeDto = new FeeDto();
        feeDto.setCommunityId(tmpAccountDto.getPartId());
        feeDto.setOwnerId(tmpAccountDto.getObjId());
        feeDto.setState(FeeDto.STATE_DOING);
        feeDto.setDeductFrom("Y");
        List<FeeDto> feeDtos = feeInnerServiceSMOImpl.queryFees(feeDto);
        if (feeDtos == null || feeDtos.size() < 1) {
            return;
        }

        StoreUserDto storeUserDto = new StoreUserDto();
        storeUserDto.setStoreId(feeDtos.get(0).getIncomeObjId());
        storeUserDto.setRelCd(StoreUserDto.REL_CD_MANAGER);
        List<StoreUserDto> storeUserDtos = storeUserV1InnerServiceSMOImpl.queryStoreUsers(storeUserDto);

        Assert.listOnlyOne(storeUserDtos,"没有扣款的用户");

        List<FeeDto> tmpFeeDtos = new ArrayList<>();
        for (FeeDto tmpFeeDto : feeDtos) {
            computeFeeSMOImpl.computeEveryOweFee(tmpFeeDto);//计算欠费金额
            //如果金额为0 就排除
            if (tmpFeeDto.getFeePrice() > 0 && tmpFeeDto.getEndTime().getTime() <= DateUtil.getCurrentDate().getTime()) {
                BigDecimal newFeePrice = new BigDecimal(tmpFeeDto.getFeePrice()+"");
                tmpFeeDto.setFeePrice(newFeePrice.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
                tmpFeeDtos.add(tmpFeeDto);
            }
        }

        if (tmpFeeDtos.size() < 1) {
            return;
        }
        Collections.sort(tmpFeeDtos,new Comparator<FeeDto>() {
            public int compare(FeeDto o1, FeeDto o2) {
                if(o1.getFeeTotalPrice() < o2.getFeeTotalPrice()){
                    return 1;
                }
                if(o1.getFeeTotalPrice()==o2.getFeeTotalPrice()){
                    return 0;
                }
                return -1;
            }

        });
        int flag = 0;
        computeFeeSMOImpl.freshFeeObjName(tmpFeeDtos);
        for (FeeDto tmpFeeDto : tmpFeeDtos) {
            Date startTime = tmpFeeDto.getEndTime();   //  0301
            //欠费月份 等于1 按照原逻辑处理， 不等于1，则循环，修改每月的结束时间
            double oweMonth =  Double.parseDouble(tmpFeeDto.getCycle());
            for (int i = 1; i <= oweMonth; i++) {
                try {
                    //重新更具费用ID查询一下，该费用的指定冲抵金额
                    AccountDto  tmpAccDto = new AccountDto();
                    tmpAccDto.setFeeId(tmpFeeDto.getFeeId());
                    tmpAccDto.setAcctId(tmpAccountDto.getAcctId());
                    List<AccountDto>  accountDtos = accountInnerServiceSMOImpl.queryAccounts(tmpAccDto);
                    if(accountDtos.size()==0){
                        continue; //无对应费项预存
                    }
                    tmpAccountDto = accountDtos.get(0);
                    //指定费项余额 如果小于 应收金额 则直接返回
                    if (tmpFeeDto.getFeePrice() > Double.parseDouble(tmpAccountDto.getFeeAmt())) {
                        continue; // 余额不足
                    }

                    Date endTime = tmpFeeDto.getEndTime(); // 最初的开始日期    1月1号
                    Date deadlineTime = tmpFeeDto.getDeadlineTime();// 最初的结束日期  2月1号

                    if(oweMonth>1&& i >1){
                        //计算下个月1号  单期费用的开始使劲按
                        Calendar cal = Calendar.getInstance();
                        cal.setTime(startTime);
                        cal.set(Calendar.MONTH, startTime.getMonth() + i-1);
                        endTime = cal.getTime();

                        Calendar cal2 = Calendar.getInstance();
                        cal2.setTime(startTime);
                        cal2.set(Calendar.MONTH,startTime.getMonth()+i);
                        deadlineTime= cal2.getTime();
                    }
                    if(oweMonth>1&& i ==1){
                        Calendar cal2 = Calendar.getInstance();
                        cal2.setTime(startTime);
                        cal2.set(Calendar.MONTH,startTime.getMonth()+1);
                        deadlineTime= cal2.getTime();
                    }


                    //先做扣款
                    AccountDetailPo accountDetailPo = new AccountDetailPo();
                    accountDetailPo.setAcctId(tmpAccountDto.getAcctId());
                    accountDetailPo.setAmount(tmpFeeDto.getFeePrice() + "");
                    accountDetailPo.setObjId(tmpAccountDto.getObjId());
                    accountDetailPo.setObjType(tmpAccountDto.getObjType());
                    accountDetailPo.setRemark("缴费扣款,费用对象："
                            + tmpFeeDto.getPayerObjName()
                            + ",费用：" + tmpFeeDto.getFeeName()
                            + ",时间：" + DateUtil.getFormatTimeString(endTime, DateUtil.DATE_FORMATE_STRING_A)
                            + "至" + DateUtil.getFormatTimeString(deadlineTime, DateUtil.DATE_FORMATE_STRING_A));
                    accountDetailPo.setDetailType(AccountDetailDto.DETAIL_TYPE_OUT);
                    accountDetailPo.setAmtType("1011"); // 扣款转出
                    accountDetailPo.setPrimeRate("9");//转物业相关费用
                    accountDetailPo.setFeeConfigId(tmpFeeDto.getConfigId());
                    flag = accountInnerServiceSMOImpl.withholdAccount2(accountDetailPo);
                    if (flag < 1) {
                        continue;//扣款失败
                    }
                    JSONObject param = new JSONObject();
                    param.put("communityId", tmpAccountDto.getPartId());
                    JSONArray fees = new JSONArray();
                    JSONObject fee = new JSONObject();
                    fee.put("feeId", tmpFeeDto.getFeeId());
                    fee.put("startTime", DateUtil.getFormatTimeString(endTime, DateUtil.DATE_FORMATE_STRING_A));
                    fee.put("endTime", DateUtil.getFormatTimeString(deadlineTime, DateUtil.DATE_FORMATE_STRING_A));
                    fee.put("receivedAmount", tmpFeeDto.getFeePrice());
                    fee.put("primeRate", "9");  //转物业相关费用
                    fee.put("remark", "定时账户扣款缴费");
                    fees.add(fee);
                    param.put("fees", fees);
                    param.put("remark", "定时账户扣款缴费");
                    try {
                        CallApiServiceFactory.postForApi(AppDto.JOB_APP_ID, param, ServiceCodeConstant.SERVICE_CODE_PAY_OWE_FEE, JSONObject.class,storeUserDtos.get(0).getUserId());
                    } catch (SMOException e) {
                        logger.error("缴费失败", e);
                        accountDetailPo = new AccountDetailPo();
                        accountDetailPo.setAcctId(tmpAccountDto.getAcctId());
                        accountDetailPo.setAmount(tmpFeeDto.getFeePrice() + "");
                        accountDetailPo.setObjId(tmpAccountDto.getObjId());
                        accountDetailPo.setObjType(tmpAccountDto.getObjType());
                        accountDetailPo.setRemark("缴费失败，费用预存");
                        accountDetailPo.setAmtType("1009");  // 虚拟存入
                        accountDetailPo.setPrimeRate("9");//转物业相关费用
                        accountDetailPo.setFeeConfigId(tmpFeeDto.getConfigId());
                        flag = accountInnerServiceSMOImpl.prestoreAccount2(accountDetailPo);
                        if (flag < 1) {
                            throw new IllegalArgumentException("费用回退失败，严重，请手工处理 " + tmpAccountDto.getAcctId() + "金额：" + tmpFeeDto.getFeePrice());
                        }
                        break;
                    }
                    if(tmpAccountDto.getAcctName().equals("泽帆地产")
                            || tmpAccountDto.getAcctName().equals("重庆心成未来教育科技有限公司")){
                        //因大业主冲抵物管费原因，所以一次冲抵一个月，这里考虑 是否添加大业主名称判断
                        break;
                    }

                } catch (Exception e) {
                    logger.error("缴费失败", e);
                    LogSystemErrorPo logSystemErrorPo = new LogSystemErrorPo();
                    logSystemErrorPo.setErrId(GenerateCodeFactory.getGeneratorId(GenerateCodeFactory.CODE_PREFIX_errId));
                    logSystemErrorPo.setErrType(LogSystemErrorDto.ERR_TYPE_ACCOUNT);
                    logSystemErrorPo.setMsg(ExceptionUtil.getStackTrace(e));
                    saveSystemErrorSMOImpl.saveLog(logSystemErrorPo);
                    logger.error("生成费用失败", e);
                }

            }


        }


        //feeId: _item,
        //                                startTime: _oweFeeItem.endTime,
        //                                endTime: _oweFeeItem.deadlineTime,
        //                                receivedAmount: _oweFeeItem.feePrice,
        //                                primeRate:$that.owePayFeeOrderInfo.primeRate

    }

}
